/*************************************************************************
    > File Name    : TcpConnection.cc
    > Author       : LiuLei
    > Mail         : 2261459486@qq.com 
    > Created Time : 2022年11月25日 星期五 11时16分23秒
 ************************************************************************/

#include "../../include/server/TcpConnection.h"
#include "../../include/server/EventLoop.h"
#include <iostream>
#include <sstream>
using std::cout;
using std::endl;
using std::ostringstream;

TcpConnection::TcpConnection(int peerfd, EventLoop *loop)
: _loop(loop)
, _socket(peerfd)
, _socketIO(peerfd)
, _localAddr(getLocalAddr())
, _peerAddr(getPeerAddr())
{

}

TcpConnection::~TcpConnection()
{

}

void TcpConnection::sendMsg(const string &msg)
{
    _socketIO.wriren(msg.c_str(), msg.size());
}

void TcpConnection::sendMsgInLoop(const string &msg)
{
    if(_loop)
    {
        _loop->runInLoop(std::bind(&TcpConnection::sendMsg, this, msg));
    }
}

string TcpConnection::recvMsg()
{
    char buff[65535] = { 0 };
    /* _socketIO.readLine(buff, sizeof(buff)); */
    _socketIO.readJson(buff, sizeof(buff));
    return string(buff);
}

string TcpConnection::addrString()
{
    ostringstream oss;
    oss << _localAddr.getIp() << ":"
        << _localAddr.getPort() << " ----> "
        << _peerAddr.getIp() << ":"
        << _peerAddr.getPort();
    
    return oss.str();
}

bool TcpConnection::isClosed() const
{
    char buf[10] = { 0 };                                         
    /* int ret = read(_socket.getFd(), buf, sizeof(buf)); */      
    int ret = ::recv(_socket.getFd(), buf, sizeof(buf), MSG_PEEK);
    return (0 == ret);
}

void TcpConnection::setConnectionCallback(const TcpConnectionCallback &cb)
{
    _onConnection = cb;
}

void TcpConnection::setMessageCallback(const TcpConnectionCallback &cb)
{
    _onMessage = cb;
}

void TcpConnection::setCloseCallback(const TcpConnectionCallback &cb)
{
    _onClose = cb;
}

/* void TcpConnection::setConnectionCallback(TcpConnectionCallback &&cb) */
/* { */                                                                    
/*     _onConnection = std::move(cb); */                                   
/* } */                                                                    
                                                                           
/* void TcpConnection::setMessageCallback(TcpConnectionCallback &&cb) */   
/* { */                                                                    
/*     _onMessage = std::move(cb); */                                      
/* } */                                                                    
                                                                           
/* void TcpConnection::setCloseCallback(TcpConnectionCallback &&cb) */     
/* { */                                                                    
/*     _onClose = std::move(cb); */                                        
/* } */                                                                   

void TcpConnection::handleConnectionCallback()
{
    if(_onConnection)
    {
        /* _onConnection(shared_ptr<TcpConnection>(this)); */
        //可能存在智能指针的误用
        _onConnection(shared_from_this());
    }
}

void TcpConnection::handleMessageCallback()
{
    if(_onMessage)
    {
        /* _onMessage(shared_ptr<TcpConnection>(this)); */
        _onMessage(shared_from_this());
    }
}

void TcpConnection::handleCloseCallback()
{
    if(_onClose)
    {
        /* _onClose(shared_ptr<TcpConnection>(this)); */
        _onClose(shared_from_this());
    }
}

InternetAddress TcpConnection::getLocalAddr() const
{
    struct sockaddr_in addr;
    
    socklen_t len = sizeof(struct sockaddr_in);
    int ret = ::getsockname(_socket.getFd(), (struct sockaddr *)&addr, &len);
    if(-1 == ret)
    {
        ::perror("getsockname in TcpConnection::getLocalAddr()");
    }

    return InternetAddress(addr);
}

InternetAddress TcpConnection::getPeerAddr() const
{
    struct sockaddr_in addr;

    socklen_t len = sizeof(struct sockaddr_in);
    int ret = ::getpeername(_socket.getFd(), (struct sockaddr *)&addr, &len);
    if(-1 == ret)
    {
        ::perror("getpeername in TcpConnection::getPeerAddr()");
    }

    return InternetAddress(addr);
}
